package com.itita.ww2.game.user;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.JsonObject;
import com.itita.ww2.core.MessageHandler;
import com.itita.ww2.core.WW2Exception;
import com.itita.ww2.data.ArmyConfig;
import com.itita.ww2.data.MissionConfig;
import com.itita.ww2.data.PlayerConfig;
import com.itita.ww2.data.shop.PaymentConfig;
import com.itita.ww2.data.shop.PaymentConfig.Category;
import com.itita.ww2.enums.PushCode;
import com.itita.ww2.game.user.UserBuildingManager.BuildingType;
import com.itita.ww2.game.user.UserRewardDispatch.IUserRewardListener;
import com.itita.ww2.game.user.UserRewardDispatch.RewardType;
import com.itita.ww2.game.user.insideevent.IUserItemChangedListener;
import com.itita.ww2.model.CodeType;
import com.itita.ww2.model.army.UserArmy;
import com.itita.ww2.model.enums.ResourceType;
import com.itita.ww2.model.item.ItemBlueprint;
import com.itita.ww2.model.item.ds.ItemValue;
import com.itita.ww2.model.item.enums.ItemBlueprintType;
import com.itita.ww2.model.item.enums.ItemPrimaryType;
import com.itita.ww2.model.item.enums.param1.P1BlueprintType;
import com.itita.ww2.model.item.enums.param2.P2TankType;
import com.itita.ww2.model.user.DevTime.DevTimeType;
import com.itita.ww2.model.user.UserProfile;
import com.itita.ww2.redis.RedisUtil;
import com.itita.ww2.redis.cache.Table;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;

/**
 * 兵兵管理器
 * @author NorthLan
 *
 */

public class UserArmyManager {
	@SuppressWarnings("unused")
	private static final Logger logger = LoggerFactory.getLogger(UserArmyManager.class);
	private int uid;
	private transient UserProfile userProfile;
	// 
	private Map<String, UserArmy> userArmyMap; // 玩家拥有的兵兵的种类

	public UserArmyManager(UserProfile userProfile) {
		this.userProfile = userProfile;
		this.uid = userProfile.getUid();
		userArmyMap = new HashMap<>();
	}

	/**
	 * 获取当前兵占用的库存量
	 */
	public int getCurArmyStock() {
		int ret = 0;
		for (UserArmy ua : userArmyMap.values()) {
			ret += ArmyConfig.getProportion(ua.getCode());
		}
		return ret;
	}

	/**
	 * 给兵种穿上装备
	 */
	public void armyEquip(String armyCode, String grid, String uuid) throws WW2Exception {
		// 兵是否解锁
		if (!isArmyUnlocked(armyCode)) {
			throw new WW2Exception();
		}
		// 穿装备
		userArmyMap.get(armyCode).equip(grid, uuid);
		update();
		syncArmy();
	}

	/**
	 * 根据code获取兵
	 */
	public UserArmy getArmy(String armyCode) {
		return userArmyMap.get(armyCode);
	}

	/**
	 * 通过一个装备的UUID获取兵
	 */
	public UserArmy getArmyByItemUUID(String uuid) {
		for (UserArmy ua : userArmyMap.values()) {
			if (ua.getEquipmentList().containsValue(uuid)) {
				return ua;
			}
		}
		return null;
	}

	/**
	 * 玩家兵力操作
	 * @param level 等级(当新增加兵时)
	 * @param additive 是否为增加操作
	 */
	public void armyCountOper(String armyCode, int count, boolean additive) {
		UserArmy ua = userArmyMap.get(armyCode);
		if (additive) {
			if (ua == null) {
				ua = new UserArmy(this.userProfile, armyCode, 1, 0, 0, false);
				userArmyMap.put(ua.getCode(), ua);
			}
			ua.countOper(count);
		} else {
			if (ua == null) {
				return;
			}
			ua.countOper(-count);
		}
	}

	/**
	 * 获取兵兵生产价格
	 */
	public int getArmyProducePrice(String armyCode, int count) {
		UserArmy army = this.userArmyMap.get(armyCode);
		return count * ArmyConfig.getArmyProducePrice(armyCode, army.getLevel());
	}

	/**
	 * 生产兵
	 */
	public boolean armyProduce(String armyCode, int count) {
		int price = getArmyProducePrice(armyCode, count);
		// 解锁条件
		if (!isArmyUnlocked(armyCode)) {
			return false;
		}
		// 兵营解锁条件
		if (!userProfile.getBDManager().isBuildingUnlocked(BuildingType.BARRACK)) {
			return false;
		}
		// 时间条件
		if (userProfile.getTimeManager().isDevTimeExists(DevTimeType.PRODUCE, armyCode)) {
			return false;
		}
		// 库存条件
		if (getCurArmyStock() >= userProfile.getUserInfo().getMaxArmyStock()) {
			return false;
		}
		// 资源条件
		if (!userProfile.getResManager().isResEnoughSingle(ResourceType.CASH, getArmyProducePrice(armyCode, count))) {
			return false;
		}
		// 全部OK,消耗资源
		userProfile.getResManager().operRes(ResourceType.CASH, -price);
		userProfile.getResManager().update();
		userProfile.getResManager().sync();
		// 设置生产数量
		this.getArmy(armyCode).produce(count);
		this.update();
		// 设置生产时间
		userProfile.getTimeManager().addDevTime(DevTimeType.PRODUCE, armyCode,
				ArmyConfig.getArmyProduceTime(armyCode) * count);
		userProfile.getTimeManager().update();
		return true;
	}

	/**
	 * 生产完成
	 */
	public void armyProduceComplete(String armyCode) {
		// DevTime dt = userProfile.getTimeManager().getDevTime(DevTimeType.PRODUCE, armyCode);
		// 生产完成
		getArmy(armyCode).produceComplete();
		this.update();
		// 移除升级时间
		userProfile.getTimeManager().removeDevTime(DevTimeType.PRODUCE, armyCode);
		userProfile.getTimeManager().update();
	}

	/**
	 * 兵是否已解锁
	 */
	public boolean isArmyUnlocked(String code) {
		if (!isArmyExists(code)) {
			return false;
		}
		return userArmyMap.get(code).isUnlocked();
	}

	/**
	 * 兵是否存在
	 */
	public boolean isArmyExists(String code) {
		return userArmyMap.containsKey(code);
	}

	/**
	 * 获取兵数量
	 */
	public int getArmyCount(String armyCode) {
		if (!isArmyExists(armyCode)) {
			return 0;
		}
		return userArmyMap.get(armyCode).getCount();
	}

	/**
	 * 获取当前正在生产的数量
	 */
	public int getArmyProduceCount(String armyCode) {
		if (!isArmyExists(armyCode)) {
			return 0;
		}
		return userArmyMap.get(armyCode).getProduceCount();
	}

	/**
	 * 解锁兵种
	 */
	public void unlockArmy(String code, int count) {
		UserArmy ua = getArmy(code);
		if (ua == null) {
			ua = new UserArmy(userProfile, code, 1, 0, count, true);
		} else {
			ua.setUnlocked(true);
		}
		userArmyMap.put(code, ua);
	}

	/**
	 * 获取玩家所有的兵
	 */
	public Collection<UserArmy> getAllUserArmy() {
		return this.userArmyMap.values();
	}

	/**
	 * 同步兵
	 */
	public synchronized void syncArmy() {
		ISFSObject pushObj = SFSObject.newInstance();
		pushObj.putSFSObject("data", toSFSObject());
		MessageHandler.getInstance().pushUser(PushCode.ARMY, pushObj, userProfile.getSFSUser());
	}

	public synchronized void load() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		ISFSObject armyObj = SFSObject.newFromJsonData(t.getValue(RedisUtil.genericKey(this.uid), "army"));
		//
		userArmyMap.clear();
		for (String key : armyObj.getKeys()) {
			UserArmy ua = UserArmy.newFromJsonData(userProfile, armyObj.getSFSObject(key));
			userArmyMap.put(key, ua);
		}
		// 
		checkAllArmyGrid();
	}

	private void checkAllArmyGrid() {
		for (Entry<String, UserArmy> entry : userArmyMap.entrySet()) {
			entry.getValue().checkGrids();
		}
		update();
	}

	public synchronized void update() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		t.setValue(RedisUtil.genericKey(this.uid), "army", toSFSObject().toJson());
	}

	public ISFSObject toSFSObject() {
		ISFSObject ret = SFSObject.newInstance();
		for (UserArmy ua : userArmyMap.values()) {
			ret.putSFSObject(ua.getCode(), ua.toSFSObject());
		}
		return ret;
	}

	private boolean isInit() {
		com.itita.ww2.redis.cache.Table t = UserService.getInstance().getCacheUserDataTable();
		String data = t.getValue(RedisUtil.genericKey(userProfile.getUid()), "army");
		return StringUtils.isNotBlank(data) && !data.equals("null");
	}

	public void initialize() {
		if (!isInit()) {
			ISFSObject config = PlayerConfig.getGameInitArmy();
			for (String key : config.getKeys()) {
				UserArmy ua = UserArmy.newFromJsonData(userProfile, config.getSFSObject(key));
				userArmyMap.put(key, ua);
			}
			this.update();
		} else {
			load();
		}
		userProfile.getRewardManager().addListener(new UserRewardImpl());
		userProfile.getInsideEventMgr().addListener(new UserItemChangedImpl());
	}

	class UserItemChangedImpl implements IUserItemChangedListener {
		@Override
		public void onUserItemChanged(ItemValue iv, ChangedType changedType) {
			if (changedType == ChangedType.MODIFY) {
				if (iv.getItem().getPrimaryType() == ItemPrimaryType.BLUEPRINT) {
					checkBlueprint(iv);
				}
			}
		}

		private void checkBlueprint(ItemValue iv) {
			ItemBlueprint ib = (ItemBlueprint) iv.getItem();
			if (ib.getP1Type() == P1BlueprintType.AUTO) {
				// 检查数量
				int needCount = ib.getEffValue();
				if (iv.getCount() >= needCount) {
					if (ib.getBlueprintType() == ItemBlueprintType.TANK) {
						String tankCode = P2TankType.getCodeByP2(ib.getParam2());
						if (isArmyUnlocked(tankCode)) {
							return;
						}
						// 解锁tankcode
						unlockArmy(tankCode, 0);
						update();
						syncArmy();
						// 扣除蓝图数量
						userProfile.getInventory().operItemCount(iv, -iv.getCount());
						// 推送解锁兵的消息
						ISFSObject pushObj = SFSObject.newInstance();
						pushObj.putUtfString("unlock", tankCode);
						MessageHandler.getInstance().pushUserEvent(null, PushCode.UNLOCK, pushObj,
								userProfile.getSFSUser());
					}
				}
			}
		}
	}

	class UserRewardImpl implements IUserRewardListener {

		@Override
		public Map<String, Object> onReward(RewardType type, ISFSObject params) throws Exception {
			Map<String, Object> ret = new HashMap<>();
			switch (type) {
			case MISSION_COMPLETE:
				ret = onMissionComplete(params.getBool("first"), params.getUtfString("missionId"),
						params.containsKey("armyKeys") ? params.getUtfStringArray("armyKeys") : null);
				break;
			case PAYMENT:
				ret = onPayment(params);
				break;
			case TIME_LIMIT_CARD:
				onTimeLimitCard(params);
				break;
			default:
				break;
			}
			return ret;
		}

		private Map<String, Object> onPayment(ISFSObject params) {
			Map<String, Object> ref = new HashMap<>();
			String sku = params.getUtfString("sku");
			Category category = PaymentConfig.getCategory(sku);
			boolean needSync = false;
			switch (category) {
			case PACK:
				{
					JsonObject armyObj = new JsonObject();
					ISFSObject content = PaymentConfig.getPackItems(sku);
					for (String key : content.getKeys()) {
						CodeType type = CodeType.codeValueOf(key);
						if (type != null && type == CodeType.ARMY) {
							armyCountOper(key, content.getInt(key), true);
							armyObj.addProperty(key, content.getInt(key));
							needSync = true;
						}
					}
					if (needSync) {
						ref.put("army", armyObj);
					}
				}
				break;
			default:
				break;
			}
			if (needSync) {
				update();
				syncArmy();
			}
			return ref;
		}

		private void onTimeLimitCard(ISFSObject rewards) {
			boolean needSync = false;
			for (String key : rewards.getKeys()) {
				CodeType type = CodeType.codeValueOf(key);
				if (type != null && type == CodeType.ARMY) {
					armyCountOper(key, rewards.getInt(key), true);
					needSync = true;
				}
			}
			if (needSync) {
				update();
				syncArmy();
			}
		}

		private Map<String, Object> onMissionComplete(boolean first, String missionId, Collection<String> armyKeys)
				throws Exception {
			Map<String, Object> ret = new HashMap<>();
			boolean needUpdateSync = false;
			if (first) {
				ISFSObject obj = MissionConfig.getUnlockData(missionId);
				for (String key : obj.getKeys()) {
					if (key.startsWith("U")) {
						unlockArmy(key, 0); // 解锁兵,但不赠送
						needUpdateSync = true;
					}
				}
			}
			if (armyKeys != null && armyKeys.size() > 0) {
				JsonObject army_exp_obj = new JsonObject();
				int army_exp = MissionConfig.getRewardArmyExp(missionId) / armyKeys.size(); // 向下取整
				for (String key : armyKeys) {
					if (!userArmyMap.containsKey(key)) {
						continue;
					}
					UserArmy ua = userArmyMap.get(key);
					if (ua.isUnlocked()) {
						// 未解锁的兵种不加经验
						ua.growExp(army_exp);
						army_exp_obj.addProperty(ua.getCode(), army_exp);
						needUpdateSync = true;
					}
				}
				ret.put("army_exp", army_exp_obj);
			}
			if (needUpdateSync) {
				update();
				syncArmy();
			}
			return ret;
		}
	}
}
